<?php if ( ! defined('BASEPATH')) exit('This file does not run directly. Sorry.'); ?>
<?php
/**
 * Kalaisoo.
 *
 * A lightweight no-framework framework written in PHP.
 *
 * @package Kalaisoo
 * @author $Author: info@sah-company.com $
 * @version $Id: gestalt.php 135 2012-01-19 01:04:55Z info@sah-company.com $
 */

/**
 * Kalaisoo Gestalt Class.
 *
 * The Gestalt outputs a certain models gestalt. It is mainly used to render HTML forms.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class Gestalt
{
	/**
	 * this array holds some templates
	 *
	 * @var array
	 */
	public $template = array(
		'label' => '<label for="%1$s">%2$s</label>',
		'help' => '<p class="help">%1$s</p>',
		'row' => array(
			'open' => '<div class="row">',
			'close' => '</div>'
		)
	);

	/**
	 * this stores the bean.
	 *
	 * @var mixed
	 */
	protected $bean;
	
	/**
	 * this stores which gestalt of the beans model should be handled.
	 *
	 * @var string
	 */
	protected $form;
	
	/**
	 * path/to/bean/1/ownBean/2.
	 *
	 * @var string
	 */
	public $path = '';
	
	/**
	 * holds the (optional) prefix for the storage name
	 *
	 * @var string
	 */
	public $prefix = '';
	
	/**
	 * holds the id of the current feature.
	 *
	 * @var string
	 */
	public $id = '';
	
	/**
	 * holds the feature counter.
	 *
	 * How many people have been crossed by now?
	 *
	 * @var string
	 */
	public $n = '';
	
	/**
	 * holds the translated label text of the current feature.
	 *
	 * @var string
	 */
	public $labelText = '';
	
	/**
	 * holds the name of the current feature.
	 *
	 * @var string
	 */
	public $name = '';

	/**
	 * holds the name of the current input element, e.g. addressbook[person][first_name].
	 *
	 * @var string
	 */
	public $fn = '';
	
	/**
	 * holds the type of the current feature.
	 *
	 * @var string
	 */
	public $type = '';
	
	/**
	 * holds the value of the current feature.
	 *
	 * @var mixed
	 */
	public $value = '';
	
	/**
	 * holds parameters array of the current feature.
	 *
	 * @var array
	 */
	public $params = array();
	
	/**
	 * holds staggered elements.
	 *
	 * @var array
	 */
	public $stack = array();
	
	/**
	 * Constructs a new Gestalt.
	 *
	 * @param mixed $bean
	 * @param string (optional) $form
	 * @param string (optional) $path
	 */
	public function __construct($bean, $form = 'default', $path = '')
	{
		$this->bean = $bean;
		$this->form = $form;
		$this->path = $path;
		Registry::instance()->addStack($bean);
	}
	
	/**
	 * returns the bean of this gestalt
	 *
	 * @return mixed
	 */
	public function bean()
	{
		return $this->bean;
	}
	
	/**
	 * returns the form of this gestalt
	 *
	 * @return string
	 */
	public function form()
	{
		return $this->form;
	}
	
	/**
	 * returns the output of all features of this beans form.
	 *
	 * @return string
	 */
	public function output()
	{
		$this->prepare();
		return implode("\n", $this->stack);
	}
	
	/**
	 * loops through all features and renders them into the stack.
	 */
	private function prepare()
	{
		$this->stack = array();
		if (empty($this->prefix)) $this->prefix = $this->bean->getMeta('type');
		$this->prepareBean();
		foreach ($this->bean->gestalt($this->form) as $n=>$f) {
			$this->prepareWorkhorse($n, $f);
		}
	}
	
	/**
	 * renders two hidden fields (type, id) to identify the bean
	 */
	private function prepareBean()
	{
		$this->fn = $this->prefix.'[type]';
		$this->value = $this->bean->getMeta('type');
		$hiddenType = new FeatureHidden($this);
		
		$this->fn = $this->prefix.'[id]';
		$this->value = $this->bean->getId();
		$hiddenId = new FeatureHidden($this);
		
		$this->stack[] = '<div>';
		$this->stack[] = $hiddenType->output();
		$this->stack[] = $hiddenId->output();
		$this->stack[] = '</div>';
	}
	
	/**
	 * actually renders the feature and pushes it into the stack
	 *
	 * @param int $n
	 * @param array $f
	 */
	private function prepareWorkhorse($n, array $f = array())
	{
		if ( ! isset($f['name'])) return false; // skip when no name is set
		if ( ! isset($f['type'])) return false; // skip when no type is set
		$this->n = $n;
		$this->params = $f;
		$this->name = $f['name'];
		$this->type = $f['type'];
		$featureName = 'Feature'.ucfirst(strtolower($this->type));
		if ( ! class_exists($featureName)) return false;
		$this->getValue();
		if (in_array($this->type, array('own', 'shared'))) {
			$this->fn = sprintf('%s[%s]', $this->prefix, $this->type.ucfirst(strtolower($this->name)));
		} else {
			$this->fn = sprintf('%s[%s]', $this->prefix, $this->name);
		}
		$this->id = md5($this->fn);
		$this->labelText = __($this->bean->getMeta('type').'_'.$this->name.'_label');
		$options = array();
		if ( isset($f['parameters'])) $options = $f['parameters'];
		$options['id'] = $this->id;
		$feature = new $featureName($this, $options);
		$this->stack[] = $this->template['row']['open'];
		if ($feature->showLabel() && $this->type != 'hidden') $this->stack[] = sprintf($this->template['label'], $this->id, $this->labelText);
		$this->stack[] = $feature->output();
		if (isset($this->params['help'])) $this->stack[] = sprintf($this->template['help'], $this->params['help']);
		$this->stack[] = $this->template['row']['close'];
		return true;
	}
	
	/**
	 * loads or dispenses the gestalts value (bean)
	 */
	public function getValue()
	{
		if ($this->type == 'nested') {
			if (isset($this->params['parameters']['alias'])) {
				if ( ! $this->value = $this->bean->fetchAs($this->params['parameters']['alias'])->{$this->name}) {
					$this->value = R::dispense($this->params['parameters']['alias']);
				}
			} else {
				if ( ! $this->value = $this->bean->{$this->name}) {
					$this->value = R::dispense($this->name);
				}
			}
		} else {
			$this->value = $this->bean->{$this->name};
		}
	}
}

/**
 * Kalaisoo Feature Class.
 *
 * A Feature is part of a beans Gestalt.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class Feature
{
	/**
	 * this holds the gestalt to which this feature clings to
	 *
	 * @var Gestalt
	 */
	protected $gestalt;
	
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<input type="%4$s" name="%1$s" %3$s value="%2$s" />';
	
	/**
	 * switch to decide wether to show a label or not
	 */
	public $showLabel = true;

	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'text';

	/**
	 * the name of this feature.
	 *
	 * @var string
	 */
	protected $name;
	
	/**
	 * the value of this feature.
	 *
	 * @mixed
	 */
	protected $value;
	
	/**
	 * the parameters array for this feature.
	 *
	 * @var array
	 */
	protected $options = array();
	
	/**
	 * Constructs a new Feature.
	 *
	 * @param Gestalt $gestalt
	 * @param array (optional) $options
	 */
	public function __construct(Gestalt $gestalt, array $options = array())
	{
		$this->gestalt = $gestalt;
		$this->options = $options;
		$this->name = $gestalt->fn;
		$this->value = $gestalt->value;
	}
	
	/**
	 * returns wether this feature generates a label element for itself or not
	 *
	 * @return bool
	 */
	public function showLabel()
	{
		return $this->showLabel;
	}
	
	/**
	 * returns the output of this feature.
	 *
	 * @return mixed
	 */
	public function output()
	{
		return sprintf($this->template, $this->name, htmlspecialchars($this->value), glue($this->options), $this->type);
	}
}

/**
 * Kalaisoo FeatureLabel Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureLabel extends Feature
{
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<label %3$s>%2$s</label>';
	
	/**
	 * returns HTML for a label.
	 *
	 * @return mixed
	 */
	public function output()
	{
		return sprintf($this->template, $this->name, $this->value, glue($this->options));
	}
}

/**
 * Kalaisoo FeatureTel Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureTel extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'tel';
}

/**
 * Kalaisoo FeatureText Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureText extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'text';
}

/**
 * Kalaisoo FeaturePassword Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeaturePassword extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'password';
}

/**
 * Kalaisoo FeatureReset Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureReset extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'reset';
}

/**
 * Kalaisoo FeatureColor Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureColor extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'color';
}

/**
 * Kalaisoo FeatureEmail Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureEmail extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'email';
}

/**
 * Kalaisoo FeatureDate Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureDate extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'date';
}

/**
 * Kalaisoo FeatureDatetime Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureDatetime extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'datetime';
}

/**
 * Kalaisoo FeatureDatetimelocal Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureDatetimelocal extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'datetime-local';
}

/**
 * Kalaisoo FeatureWeek Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureWeek extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'week';
}

/**
 * Kalaisoo FeatureMonth Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureMonth extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'month';
}

/**
 * Kalaisoo FeatureUrl Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureUrl extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'url';
}

/**
 * Kalaisoo FeatureNested Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureNested extends Feature
{
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<div class="wrapper" id="%1$s">%2$s</div>';
	
	/**
	 * the template for the hidden type field when nested option select is used.
	 *
	 * @var string
	 */
	protected $templateHidden = '<input type="hidden" name="%1$s" value="%2$s" />';
	
	/**
	 * the template for the label field when nested option select is used.
	 *
	 * @var string
	 */
	protected $templateLabel = '<label for="%1$s">%2$s</label>';
	
	/**
	 * holds the nested bean
	 */
	protected $bean;
	
	/**
	 * switch to decide wether to show a label or not
	 */
	public $showLabel = false;
	
	/**
	 * returns the output of this feature.
	 *
	 * @return mixed
	 */
	public function output()
	{
		if (isset($this->options['select'])) return $this->outputSelect();
		return $this->outputStandard();
	}
	
	/**
	 * returns the standard output of this feature.
	 *
	 * @return string
	 */
	private function outputStandard()
	{
		$gestalt = new Gestalt($this->gestalt->value, $this->gestalt->form());
		$gestalt->prefix = $this->gestalt->fn;
		$subgestalt = $gestalt->output();
		return sprintf($this->template, $this->gestalt->id, $subgestalt);
	}
	
	/**
	 * returns the output of this feature where the nested record is selectable
	 *
	 * @return string
	 */
	private function outputSelect()
	{
		$gestalt = new Gestalt($this->gestalt->value);
		$gestalt->fn = $this->gestalt->fn.'[id]';
		$gestalt->value = $this->gestalt->value->getId();
		$id = md5($gestalt->fn);
		$options = array(
			'id' => $id,
			'dynamic' => array(
				'model' => isset($this->options['alias']) ? $this->options['alias'] : $this->gestalt->value->getMeta('type'),
				'key' => 'id',
				'name' => $this->options['select']
			)
		);
		if (isset($this->options['null'])) {
			// the select options should include a first value that is NULL
			$options['null'] = $this->options['null'];
		}
		$feature = new FeatureSelect($gestalt, $options);
		$output = sprintf($this->templateHidden, $this->gestalt->fn.'[type]', isset($this->options['alias']) ? $this->options['alias'] : $this->gestalt->value->getMeta('type'))."\n";
		$output .= sprintf($this->templateLabel, $id, $this->gestalt->labelText)."\n";
		$output .= $feature->output()."\n";
		return sprintf($this->template, $this->gestalt->id, $output);
	}
}

/**
 * Kalaisoo FeatureGroup Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureGroup extends Feature
{
	/**
	 * defines this group type.
	 *
	 * @var string
	 */
	protected $groupType = '';
	
	/**
	 * stores the name of the container.
	 *
	 * If you handle e.g. an 'email' this will be 'ownEmail' as the container name
	 */
	protected $container = '';

	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<div class="wrapper"><a href="%3$s" data-target="%1$s" class="attach"><span>attach</span></a><div id="%1$s">%2$s</div></div>';
	
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $templateBean = '<div class="item" id="%3$s"><a href="%2$s" data-target="%3$s" class="detach"><span>detach</span></a> %1$s</div>';
	
	/**
	 * template for the action url.
	 *
	 * Replace with language, action, master bean type, master bean id, path.
	 *
	 * @var string
	 */
	protected $templateActionUrl = '%s/%s/%s/%s/%s/?path=%s';
	
	
	/**
	 * holds the path within the structure
	 *
	 * @var string
	 */
	public $path = '';
	
	/**
	 * holds all own(ed) beans
	 */
	protected $beans = array();
	
	/**
	 * holds the current own(ed) bean
	 */
	protected $bean;
	
	/**
	 * switch to decide wether to show a label or not
	 */
	public $showLabel = false;
	
	/**
	 * returns the output of this feature.
	 *
	 * @return string
	 */
	public function output()
	{
		$type = $this->gestalt->params['name'];
		$this->container = $this->groupType.ucfirst(strtolower($type));
		$this->path .= $this->gestalt->path.$this->container.'/'.$this->gestalt->bean()->getId().'/';
		//Registry::instance()->loader->model($type, true);
		$this->beans = $this->gestalt->bean()->{$this->container};
		if ( ! $this->beans) {
			$this->beans = array(R::dispense($type));
		}
		$s = array();
		$stack = Registry::instance()->stack();
		foreach ($this->beans as $n=>$this->bean) {
			/*
			$gestalt = new Gestalt($this->bean, $this->gestalt->form(), $this->path);
			$gestalt->prefix = $this->gestalt->fn.'['.$n.']';
			$itemId = md5($gestalt->prefix);
			$actionUrl = ahref(sprintf($this->templateActionUrl, Registry::instance()->language, 'detach', $stack[0]->getMeta('type'), $stack[0]->getId(), urlencode($this->path)));
			$s[] = sprintf($this->templateBean, $gestalt->output(), $actionUrl, $itemId);
			*/
			$s[] = $this->subGestalt($this->bean, $n, $stack[0], $this->gestalt->path);
		}
		$actionUrl = ahref(sprintf($this->templateActionUrl, Registry::instance()->language, Registry::instance()->router->controller(), 'attach', $stack[0]->getMeta('type'), $stack[0]->getId(), urlencode($this->path)));
		return sprintf($this->template, $this->gestalt->id, implode("\n", $s), $actionUrl);
	}
	
	/**
	 * returns the output of a sub gestalt
	 */
	public function subGestalt($bean, $n, $rootBean, $path)
	{
		$path = $path.$this->container.'/'.$bean->getId().'/';
		$gestalt = new Gestalt($bean, $this->gestalt->form(), $path);
		$gestalt->prefix = $this->gestalt->fn.'['.$n.']';
		$itemId = md5($gestalt->prefix);
		$actionUrl = ahref(sprintf($this->templateActionUrl, Registry::instance()->language, Registry::instance()->router->controller(), 'detach', $rootBean->getMeta('type'), $rootBean->getId(), urlencode($path)));
		return sprintf($this->templateBean, $gestalt->output(), $actionUrl, $itemId);
	}
}

/**
 * Kalaisoo FeatureOwn Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureOwn extends FeatureGroup
{
	/**
	 * defines this group type.
	 *
	 * @var string
	 */
	protected $groupType = 'own';
}

/**
 * Kalaisoo FeatureShared Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureShared extends FeatureGroup
{
	/**
	 * defines this group type.
	 *
	 * @var string
	 */
	protected $groupType = 'shared';
}

/**
 * Kalaisoo FeatureSubmit Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureSubmit extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'submit';
}

/**
 * Kalaisoo FeatureCheckbox Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureCheckbox extends Feature
{
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<input type="checkbox" name="%1$s" %3$s />';
	
	/**
	 * returns the output of this feature.
	 *
	 * @return mixed
	 */
	public function output()
	{
		if ($this->value == $this->options['value']) $this->options['checked'] = 'checked';
		return sprintf($this->template, $this->name, htmlspecialchars($this->value), glue($this->options));
	}
}

/**
 * Kalaisoo FeatureRadio Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureRadio extends FeatureSelect
{
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<label>%2$s</label> %1$s';

	/**
	 * the template for a radio button input element.
	 *
	 * @var string
	 */
	protected $templateRadio = '<input type="radio" id="%5$s" name="%1$s" %2$s value="%4$s" /> %3$s';
	
	/**
	 * the template for a label element
	 *
	 * @var string
	 */
	protected $templateLabel = '<label for="%1$s">%2$s</label>';
	
	/**
	 * switch to decide wether to show a label or not
	 */
	public $showLabel = false;
	
	/**
	 * returns a string with all radio buttons options HTML.
	 *
	 * @return string
	 */
	protected function options() {
		$s = array();
		foreach ($this->optionValues as $key=>$option) {
			$selected = null;
			if (is_array($this->value)) {
				if (in_array($key, $this->value)) {
					$selected = ' selected="selected"';
				}
			} elseif ($this->value == $key) {
				$selected = ' selected="selected"';
			}
			$fid = md5($this->name.'-'.$key);
			$label = sprintf($this->templateLabel, $fid, $option);
			$s[] = sprintf($this->templateRadio, $this->name, $selected, $label, $key, $fid);
		}
		return implode("\n", $s);
	}
	
	/**
	 * returns the output of this feature.
	 *
	 * @return mixed
	 */
	public function output()
	{
		$this->prepareOptions();
		return sprintf($this->template, $this->options(), $this->gestalt->labelText);
	}
}

/**
 * Kalaisoo FeatureRange Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureRange extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'range';
}

/**
 * Kalaisoo FeatureNumber Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureNumber extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'number';
}

/**
 * Kalaisoo FeatureHidden Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureHidden extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'hidden';
}

/**
 * Kalaisoo FeatureTextarea Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureTextarea extends Feature
{
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<textarea name="%1$s" %3$s>%2$s</textarea>';
	
	/**
	 * returns the output of this feature.
	 *
	 * @return mixed
	 */
	public function output()
	{
		return sprintf($this->template, $this->name, htmlspecialchars($this->value), glue($this->options));
	}
}

/**
 * Kalaisoo FeatureFile Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureFile extends Feature
{
	/**
	 * the template.
	 *
	 * @var string
	 */
	protected $template = '<input type="hidden" name="MAX_FILE_SIZE" value="%2$s" /><input type="file" name="uploaded_file" %3$s />';
	
	/**
	 * returns the output of this feature.
	 *
	 * @return mixed
	 */
	public function output()
	{
		$s = array();
		$s[] = $this->preview();
		$s[] = sprintf($this->template, $this->name, Registry::instance()->config['uploads']['max_file_size'], glue($this->options));
		return implode("\n", $s);
	}
	
	/**
	 * returns a string with HTML to preview a file.
	 *
	 * @return string
	 */
	function preview()
	{
		if ( ! $this->value) return '';
		$s = array();
		$s[] = '<a class="preview" href="'.ahref(Registry::instance()->config['uploads']['path'].'/'.$this->value).'">';
		$s[] = '<span>'.htmlspecialchars($this->value).'</span>';
		$s[] = '</a>';
		return implode("\n", $s);
	}
}

/**
 * Kalaisoo FeatureSearch Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureSearch extends Feature
{
	/**
	 * the type of this feature.
	 *
	 * @var string
	 */
	protected $type = 'search';
}

/**
 * Kalaisoo FeatureSelect Class.
 *
 * @package Kalaisoo
 * @subpackage System
 * @author $Author: info@sah-company.com $
 */
class FeatureSelect extends Feature
{
	/**
	 * the template for the select input element.
	 *
	 * @var string
	 */
	protected $template = '<select name="%1$s" %3$s>%2$s</select>';
	
	/**
	 * the template for an option.
	 *
	 * @var string
	 */
	protected $templateOption = '<option value="%1$s" %2$s>%3$s</option>';
	
	/**
	 * holds the select field options
	 *
	 * @var array
	 */
	protected $optionValues = array();
	
	/**
	 * returns the output of this feature.
	 *
	 * @return mixed
	 */
	public function output()
	{
		$this->prepareOptions();
		if (isset($this->options['null'])) {
			//$this->optionValues = array('__none__' => $this->options['null']) + $this->optionValues;
			array_unshift($this->optionValues, $this->options['null']);
		}
		return sprintf($this->template, $this->name, $this->options(), glue($this->options));
	}
	
	/**
	 * set $this->optionValues depending on this features parameters.
	 *
	 * This will either load static, dynamic or session based option values. If the feature
	 * options has a property 'null' that value is used as the first entry.
	 *
	 * @return bool
	 */
	private function prepareOptions()
	{
		if (isset($this->options['dynamic'])) return $this->prepareOptionsDynamic();
		if (isset($this->options['options'])) return $this->prepareOptionsStatic();
		if (isset($this->options['session'])) return $this->prepareOptionsSession();
	}
	
	/**
	 * sets $optionValues from static values
	 *
	 * @return bool
	 */
	private function prepareOptionsStatic()
	{
		$this->optionValues = $this->options['options'];
		unset($this->options['options']);
		return true;
	}
	
	/**
	 * sets $optionValues from a session variable
	 *
	 * @return bool
	 */
	private function prepareOptionsSession()
	{
		if ( ! isset($_SESSION[$this->options['session']])) return false;
		$this->optionValues = $_SESSION[$this->options['session']];
		unset($this->options['session']);
		return true;
	}
	
	/**
	 * sets $optionValues from a database query
	 *
	 * @return bool
	 */
	private function prepareOptionsDynamic()
	{
		if ( ! is_array($this->options['dynamic'])) return false;
		if ( ! isset($this->options['dynamic']['model'])) return false;
		if ( ! isset($this->options['dynamic']['name'])) return false;
		if ( ! isset($this->options['dynamic']['key'])) return false;
		Registry::instance()->loader->model($this->options['dynamic']['model']);
		$records = R::find($this->options['dynamic']['model']);
		$fn = $this->options['dynamic']['name'];
		$key = $this->options['dynamic']['key'];
		foreach ($records as $n=>$record) {
			$this->optionValues[$record->$key] = $record->$fn;
		}
		unset($this->options['dynamic']);
		return true;
	}
	
	/**
	 * returns a string with select options HTML.
	 *
	 * @return string
	 */
	private function options() {
		$s = array();
		foreach ($this->optionValues as $key=>$option) {
			$selected = null;
			if (is_array($this->value)) {
				if (in_array($key, $this->value)) {
					$selected = ' selected="selected"';
				}
			} elseif ($this->value == $key) {
				$selected = ' selected="selected"';
			}
			$s[] = sprintf($this->templateOption, $key, $selected, $option);
		}
		return implode("\n", $s);
	}
}
?>